iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0
自我挑戰組

JS 加強筆記系列 第 29

Day 29:macrotask 與 microtask (2)

  • 分享至 

  • xImage
  •  

問題 1

console.log('start');

setTimeout(() => {
    console.log('setTimeout');
});

Promise.resolve().then(function() {
    console.log('promise');
});

console.log('end');

這段程式碼來自這個問題,會印出:

"start"
"end"
"promise"
"setTimeout"

基於昨天寫的 event loop 步驟,可能會對於這個結果有點意外,因為會以為順序是執行完同步程式碼後會先做一件 macrotask 再做 microtask,所以誤認為 'setTimeout' 會早於 'promise'。

針對這裡會先執行 microtask 這點有看到幾種說法,一種是如同 stack overflow 的回答所說,執行 JS script 本身也是一個 macrotask,所以 call stack 空了以後會執行 microtask。這篇文章有寫到比較具體的過程:

At the execution of any JS file, the JS engine wraps the contents in a function and associates the function with an event either start or launch. The JS engine emits the start event, the events are added to the task queue (as a macrotask).

另一類說法比較不像解釋,而是一開始就強調 microtask 優先順序較高,所以當 call stack 空了之後會先檢查 microtask queue,然後才檢查 macrotask。(但因為 event loop 不斷循環,所以個人理解這裡所謂的優先比較是循環從 microtask 起算的感覺。)

但無論是哪種,至少都不違背主要的原則:每次循環執行一件 macrotask,而 microtask 則會穿插在每個 macrotask 之間執行直到 microtask queue 為空。

問題 2

console.log('start here');

const foo = () => (new Promise((resolve) => {
    console.log('first promise constructor');

    let promise1 = new Promise((resolve) => {
        console.log('second promise constructor');

        setTimeout(() => {
            console.log('setTimeout');
            resolve();
        }, 0)

        resolve('promise1')
    })

    resolve('promise0')

    promise1.then(arg => {
        console.log(arg);
    })
}))

foo().then(arg => {
    console.log(arg);
})

console.log('end here');

這是在《前端工程》裡看到的例子,會印出:

"start here"
"first promise constructor"
"second promise constructor"
"end here"
"promise1"
"promise0"
"setTimeout"

程式碼一長看起來就有點複雜,但還是維持同步 -> microtask -> macrotask 的順序。

現在看這種問題稍微不怕,而且思考有點依據,也算是了結關於 promise 的一樁心事,但我衷心希望面試可以多多討論原則就好。


上一篇
Day 28:macrotask 與 microtask (1)
下一篇
Day 30:promise、幻覺、平常心
系列文
JS 加強筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言